#pragma once
#include "mock_C++_thread.hpp"
#include "task.hpp"
#include <iostream>
#include <queue>

#define THREAD_NUM 5
#define TASK_NUM 20

template<class T>
class thread_pool;

template <class T>
class thread_data{
public:
    std::string _name;
    thread_pool<T> *_trs;

    thread_data(const char* name, thread_pool<T>* trs)
    :_name(name), _trs(trs){};
};

template <class T>
class thread_pool
{
public:
    
    thread_pool()
    {
        pthread_mutex_init(&_mutex, NULL);
        pthread_cond_init(&_cond, NULL);
        for (int i = 0; i < THREAD_NUM; i++)
        {
           _threads.push_back(new mock_thread);
        }
    }

    void run()
    {
        for(int i = 0; i < THREAD_NUM; i++)
        {
            char name[64];
            snprintf(name, sizeof(name)-1, "我是%d号线程", i);
            thread_data<T> * td = new thread_data<T>(name, this);
            _threads[i]->start(routine, (void*)td);
        }
    }

    bool push(const T value)
    {
        if (if_full())
        {
            pthread_cond_broadcast(&_cond);
            return false;
        }

        _task.push(value);
        pthread_cond_signal(&_cond);
        return true;
    }

    ~thread_pool()
    {
        pthread_mutex_destroy(&_mutex);
        pthread_cond_destroy(&_cond);
        for (const auto &t : _threads)
            delete t;
    }

private:

    void lock()
    {
        pthread_mutex_lock(&_mutex);
    }

    void unlock()
    {
        pthread_mutex_unlock(&_mutex);
    }

    void wait()
    {
        pthread_cond_wait(&_cond, &_mutex);
    }

private:

    static void* routine(void* args)
    {
        thread_data<T> *_test = (thread_data<T> *)args;
        while(true)
        {
            _test->_trs->lock();

            while(_test->_trs->if_empty())
            {
                _test->_trs->wait();
            }

            T t = _test->_trs->_task.front();
            _test->_trs->_task.pop();
            _test->_trs->unlock();

            t();
            std::cout<<_test->_name <<"任务已完成" << std::endl;
        }

        delete _test;
        return nullptr;
    }

    bool if_empty()
    {
        return _task.empty();
    }

    bool if_full()
    {
        if (_task.size() >= TASK_NUM)
            return true;
        return false;
    }

private:
    std::queue<T> _task;
    pthread_mutex_t _mutex;
    pthread_cond_t _cond;
    std::vector<mock_thread* > _threads;
};
